// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//
#pragma once
#include <string>
#include <turbo/container/flat_hash_map.h>
#include <turbo/utility/status.h>
#include <turbo/log/logging.h>

namespace cantor {

    struct EnumData {
        bool allow_alias{false};
        bool has_alias{false};
        std::string uri;
        turbo::flat_hash_map<uint32_t, std::vector<std::string> > value_to_name;
        turbo::flat_hash_map<std::string, uint32_t> name_to_value;
        uint32_t max_value{0};
        turbo::uint128 fingerprint{};
        turbo::Status status;

        operator bool() const {
            return status.ok();
        }
        bool ok() const {
            return status.ok();
        }

        std::string to_string() const;

        void check_sum();

        bool operator==(const EnumData& other) const;
    };
    class EnumBuilder {
    public:
        EnumBuilder() = default;
        EnumBuilder(const EnumBuilder&) = delete;
        EnumBuilder& operator=(const EnumBuilder&) = delete;

        void allow_alias(bool allow_alias) {
            _allow_alias = allow_alias;
        }

        void set_uri(const std::string& uri) {
            KCHECK(!_final);
            _uri = uri;
        }

        turbo::Status emplace(const std::string &name, uint32_t value);
        turbo::Status emplace(const std::string &name);

        bool valid() const {
            return _status.ok();
        }

        turbo::Status status() const {
            return _status;
        }

        std::string to_string() const;

        turbo::Status is_name_conflict(const std::string &name) const;
        turbo::Status is_value_conflict(uint32_t value, bool &has_alias) const;

        EnumData build() &&;
    private:
        const turbo::flat_hash_map<uint32_t, std::vector<std::string> >& values() const &{
            return _value_to_name;
        }

        const turbo::flat_hash_map<std::string, uint32_t> &names_value() const &{
            return _name_to_value;
        }

        uint32_t max_value() const {
            return _max_value;
        }

        const std::string &uri() const {
            return _uri;
        }
        turbo::Status is_name_conflict_impl(const std::string &up_name, const std::string &name) const;
        turbo::Status final_status();
        turbo::Result<uint32_t> find_value(const std::string &name) const;
    private:
        bool _final{false};
        bool _allow_alias{false};
        bool _has_alias{false};
        std::string _uri;
        turbo::flat_hash_map<uint32_t, std::vector<std::string> > _value_to_name;
        turbo::flat_hash_map<std::string, uint32_t> _name_to_value;
        uint32_t _current_value{0};
        uint32_t _max_value{0};
        turbo::Status _status;
    };
} // namespace cantor
